package geowiki.utils;

import processing.core.PApplet;
import processing.core.PVector;

public class MathUtils {

	/**
	 * 
	 * @param cx
	 *            x of center point of the circular arc
	 * @param cy
	 *            y of center point of the circular arc
	 * @param radius
	 *            Radius of the circular arc
	 */
	public static PVector[] getBezierVertexPoints(float cx, float cy, float radius, float startAngle, float theta) {
		PVector[] vectors = new PVector[4];

		// Compute raw Bezier coordinates.
		float x0 = PApplet.cos(theta / 2.0f);
		float y0 = PApplet.sin(theta / 2.0f);
		float x3 = x0;
		float y3 = 0 - y0;
		float x1 = (4.0f - x0) / 3.0f;
		float y1 = ((1.0f - x0) * (3.0f - x0)) / (3.0f * y0); // y0 != 0...
		float x2 = x1;
		float y2 = 0 - y1;

		// Compute rotationally-offset Bezier coordinates, using:
		// x' = cos(angle) * x - sin(angle) * y;
		// y' = sin(angle) * x + cos(angle) * y;
		float bezAng = startAngle + theta / 2.0f;
		float cBezAng = PApplet.cos(bezAng);
		float sBezAng = PApplet.sin(bezAng);
		float rx0 = cBezAng * x0 - sBezAng * y0;
		float ry0 = sBezAng * x0 + cBezAng * y0;
		float rx1 = cBezAng * x1 - sBezAng * y1;
		float ry1 = sBezAng * x1 + cBezAng * y1;
		float rx2 = cBezAng * x2 - sBezAng * y2;
		float ry2 = sBezAng * x2 + cBezAng * y2;
		float rx3 = cBezAng * x3 - sBezAng * y3;
		float ry3 = sBezAng * x3 + cBezAng * y3;

		// Compute scaled and translated Bezier coordinates.
		float px0 = cx + radius * rx0;
		float py0 = cy + radius * ry0;
		float px1 = cx + radius * rx1;
		float py1 = cy + radius * ry1;
		float px2 = cx + radius * rx2;
		float py2 = cy + radius * ry2;
		float px3 = cx + radius * rx3;
		float py3 = cy + radius * ry3;
		vectors[0] = new PVector(px0, py0);
		vectors[1] = new PVector(px1, py1);
		vectors[2] = new PVector(px2, py2);
		vectors[3] = new PVector(px3, py3);

		return vectors;
	}

	/**
	 * Calculates angle between two points, i.e. between the sum vector and the x-axis.
	 * 
	 * @param p1
	 *            The first point.
	 * @param p2
	 *            The second point.
	 * @return The angle between both points.
	 */
	public static float getAngleBetween(PVector p1, PVector p2) {
		// Note: Raw values between point 1 and point 2 not valid, as they are are origin-based.
		PVector sub = PVector.sub(p1, p2);
		PVector xaxis = new PVector(1, 0);
		float angle = PVector.angleBetween(sub, xaxis);

		if (p1.y < p2.y) {
			angle = PApplet.TWO_PI - angle;
		}
		return angle;
	}

	/**
	 * Calculates distance between two points, i.e. between the sum vector and the x-axis.
	 * 
	 * @param p1
	 *            The first point.
	 * @param p2
	 *            The second point.
	 * @return The distance between both points.
	 */
	public static float getDistanceBetween(PVector p1, PVector p2) {
		// Note: Raw values between point 1 and point 2 not valid, as they are are origin-based.
		PVector sub = PVector.sub(p1, p2);
		PVector xaxis = new PVector(1, 0);
		float dist = PVector.dist(sub, xaxis);
		return dist;
	}

}
